﻿@using DialogOptions = MudBlazor.DialogOptions
@inject NavigationManager NavigationManager
@inject ContextMenuService contextMenuService
@inject SelectionService selectionService
@inject ISearchService searchService
@inject NavigationService navContext
@inject IUserBasketService basketService
@inject IFileService fileService
@inject IDownloadService downloadService
@inject ClientUIStateService uiService
@inject ILogger<GridImage> logger
@inject IDialogService DialogService
@inject IImageCacheService imageCache

@inject IJSRuntime JsRuntime

<LocalFileExporter @ref="FileExporter"/>

@if( CurrentImage == null )
{
    <div title="Loading image..." class="imagegrid-loader"></div>
}
else
{
    <div class="grid-image" @ondblclick="NavigateToImage" @onclick=OnClick>
        @if ( !string.IsNullOrEmpty(ImageUrl) )
        {
            <img @key="CurrentImage.ImageId" style="@ImageStyle" class="@ImageClass @FadeClass"
                 @onload="PreloadCompleted" title="@ImgToolTip" src="@ImageUrl"
                 @oncontextmenu=@(args => ShowContextMenu(args)) @oncontextmenu:preventDefault="true">
            <input class=" grid-checkbox damselfly-checkbox" type="checkbox" @bind="@InBasket">
        }
    </div>
    @if( DisplayFileName )
    {
        <div class="grid-image-text">
            @CurrentImage.FileName
        </div>
    }
}

@code
{
    private string ImageStyle { get; set; }

    private void GenerateImageStyle()
    {
        int size;
        if( uiService.IsSmallScreenDevice )
        {
            const int imageGap = 2;
            var targetImagesPerRow = uiService.IsPortraitDevice ? 4 : 6;

            size = GridImageSize switch
            {
                GridImageSize.Medium => 150,
                GridImageSize.Large => 250,
                GridImageSize.Mini => 50,
                // Small is the default
                _ => int.Max( uiService.ScreenWidth / targetImagesPerRow - (targetImagesPerRow - 1) * imageGap, 50)
            };
        }
        else
        {
            size = GridImageSize switch
            {
                GridImageSize.Medium => 250,
                GridImageSize.Large => 400,
                GridImageSize.Mini => 65,
                _ => 120 // Small is the default
            };
        }

        var aspectStyle = ThumbnailSize == ThumbSize.Small || CurrentImage.MetaData == null ? string.Empty : $"aspect-ratio:{CurrentImage.MetaData.AspectRatio:0.##};";
        ImageStyle = $"height: {size}px; min-height: {size}px; width: auto; min-width: {size}px; {aspectStyle}";
    }

    [Parameter] public EventCallback<MouseEventArgs> OnClick { get; set; }

    [Parameter] public NavigationContexts NavContext { get; set; }

    [Parameter] public Image CurrentImage { get; set; }

    [Parameter] public bool DisplayFileName { get; set; } = false;

    [Parameter] public GridImageSize GridImageSize { get; set; } = GridImageSize.Small;

    private ThumbSize ThumbnailSize => GridImageSize switch
    {
        GridImageSize.Large => ThumbSize.Large,
        GridImageSize.Medium => ThumbSize.Medium,
        GridImageSize.Mini => ThumbSize.Small,
        _ => ThumbSize.Small
    };

    public bool InBasket
    {
        get => basketService.IsInCurrentBasket(CurrentImage);
        set => _ = SetImageBasketState(value);
    }

    private string theClass => $"{ImageClass} {FadeClass}";
    private LocalFileExporter FileExporter;
    private string ImgToolTip => CurrentImage == null ? "No info" : $"{CurrentImage.FileName}\nTaken: {CurrentImage.SortDate.Display()}\nFolder: {CurrentImage.Folder.Path}\n{ImageSize}";
    private string ImageUrl => CurrentImage.ThumbUrl(ThumbnailSize);
    private string previewKey => $"Prev{CurrentImage.ImageId}";
    private string ImageSize => CurrentImage.MetaData == null ? "n/a" : $"Size (w x h): {CurrentImage.MetaData.Width} x {CurrentImage.MetaData.Height}";
    private string ImageClass => selectionService.IsSelected(CurrentImage) ? "grid-image-selected" : "grid-image-unselected";
    private string FadeClass = string.Empty;
    private int imageId = 0;

    private async Task SetImageBasketState(bool newState)
    {
        await basketService.SetImageBasketState(newState, new[] { CurrentImage.ImageId });

        // Notify the image list that the selection has changed
        StateHasChanged();
    }

    protected void PreloadCompleted(ProgressEventArgs args)
    {
        FadeClass = "grid-image-fadein";
        imageId = CurrentImage.ImageId;
        StateHasChanged();
    }

    protected override void OnParametersSet()
    {
        base.OnParametersSet();

        if( CurrentImage == null || CurrentImage.ImageId != imageId )
            FadeClass = string.Empty;

        GenerateImageStyle();
    }

    void ShowContextMenu(MouseEventArgs args)
    {
        var selectedImages = selectionService.Selection;

        contextMenuService.Open(args, ds =>
            @<CascadingAuthenticationState>
                <RadzenMenu Click="OnMenuItemClick">
                    <RadzenMenuItem Text="View Image" Value="0"/>
                    <AuthorizeView Policy="@PolicyDefinitions.s_IsDownloader">
                        <RadzenMenuItem Text="Download" Value="1"/>
                    </AuthorizeView>
                    @if ( CurrentImage.Hash != null && CurrentImage.Hash.HasPerceptualHash() )
                    {
                        <RadzenMenuItem Text="Find Similar Images" Value="6"/>
                    }
                    <RadzenMenuItem Text="View Folder" Value="7"/>
                    <RadzenMenuItem Text="View Images From This Day" Value="8"/>
                    <hr class="separator">
                    @if ( InBasket )
                    {
                        <RadzenMenuItem Text="Remove from basket" Value="2"/>
                    }
                    else
                    {
                        <RadzenMenuItem Text="Add to basket" Value="3"/>
                    }
                    @if ( FileExporter != null && FileExporter.IsDesktopHosted )
                    {
                        <AuthorizeView Policy="@PolicyDefinitions.s_IsDownloader">
                            <RadzenMenuItem Text="Save Locally" Value="4"/>
                        </AuthorizeView>
                    }

                    <AuthorizeView Policy="@PolicyDefinitions.s_IsAdmin">
                        <RadzenMenuItem Text="Refresh" Value="5"/>
                        <hr class="separator">
                        <RadzenMenuItem Text="Delete from Disk" Value="9"/>
                    </AuthorizeView>
                </RadzenMenu>
            </CascadingAuthenticationState>);
    }

    private ICollection<Image> ContextSelection
    {
        get
        {
            if( selectionService.Selection.Any() )
            {
                return selectionService.Selection;
            }

            return new List<Image> { CurrentImage };
        }
    }

    async Task OnMenuItemClick(MenuItemEventArgs args)
    {
        contextMenuService.Close();
        switch( args.Value )
        {
            case 0:
                NavigateToImage();
                break;
            case 1:
                await DownloadImage();
                break;
            case 2:
                await basketService.SetImageBasketState(false, ContextSelection.Select(x => x.ImageId).ToList());
                break;
            case 3:
                await basketService.SetImageBasketState(true, ContextSelection.Select(x => x.ImageId).ToList());
                break;
            case 4:
                await FileExporter.ExportImagesToLocalFilesystem(ContextSelection);
                break;
            case 5:
                await ShowRescanDialog();
                break;
            case 6:
                FindImageSimilarTo();
                break;
            case 7:
                GoToImageFolder();
                break;
            case 8:
                FilterByImageDate();
                break;
            case 9:
                await DeleteImages(ContextSelection.Select(x => x.ImageId).ToList());
                break;
        }
    }

    private async Task DeleteImages( ICollection<int> imageIds )
    {
        var req = new MultiImageRequest { ImageIDs = imageIds };
        await fileService.DeleteImages(req);
    }

    private async Task ShowRescanDialog()
    {
        var parameters = new DialogParameters { { "images", ContextSelection } };
        var options = new DialogOptions { MaxWidth = MaxWidth.ExtraSmall, BackdropClick = false };
        var dialog = DialogService.Show<RescanDialog>("Re-scan Images", parameters, options);
        var result = await dialog.Result;
    }

    private void  GoToImageFolder()
    {
        NavigationManager.NavigateTo( $"/?folderId={CurrentImage.Folder.FolderId}" );
    }

    private void FilterByImageDate()
    {
        var url = $"/?date={CurrentImage.SortDate:dd-MMM-yyyy}";
        NavigationManager.NavigateTo(url);
    }

    private void FindImageSimilarTo()
    {
        searchService.SimilarToId = CurrentImage.ImageId;
    }

    public async Task DownloadImage()
    {
        try
        {
            var downloadFile = CurrentImage.DownloadImageUrl;

            if( selectionService.Selection.Count() > 1 )
            {
                var config = new ExportConfig { KeepFolders = true };
                downloadFile = await downloadService.CreateDownloadZipAsync(selectionService.Selection.Select(x => x.ImageId).ToList(), config);
            }

            await JsRuntime.InvokeAsync<string>("downloadFile", downloadFile);
        }
        catch( Exception ex )
        {
            logger.LogError("Exception: " + ex.Message);
        }
    }

    void NavigateToImage()
    {
        navContext.Context = NavContext;
        NavigationManager.NavigateTo("/image/" + CurrentImage.ImageId);
    }
}